home *** CD-ROM | disk | FTP | other *** search
- /*
- * _read_symdir(), _write_symdir(), _free_symdir(): routines for
- * reading/writing the special directories used for symbolic links.
- * If symbolic links were not set active in UNIXMODE, then theses
- * routines are no-ops.
- *
- * Written by Eric R. Smith and placed in the public domain. Use
- * at your own risk.
- */
-
- #include <stdio.h>
- #include <osbind.h>
- #include <string.h>
- #include <stdlib.h>
- #include <errno.h>
- #include "symdir.h"
-
- #ifndef NAME_MAX
- # include <limits.h>
- #endif
-
- #ifndef _LIB_NAME_MAX
- # define _LIB_NAME_MAX NAME_MAX
- #endif
-
- /*
- * utility routine to provide buffered I/O for _read_symdir()
- */
-
- #define ResetFgetc() Fgetc(-1)
-
- static int Fgetc(fd)
- int fd;
- {
- static unsigned char buf[BUFSIZ], *pos;
- static int siz = 0;
-
- if (fd < 0) {
- siz = 0; pos = buf; return 0;
- }
-
- if (siz == 0) {
- siz = Fread(fd, BUFSIZ, buf);
- pos = buf;
- if (siz <= 0) {
- siz = 0; pos = buf; return -1;
- }
- }
- siz--;
- return *pos++;
- }
-
-
- /*
- * Routines for keeping a cache of recently used symbolic directories.
- * The last 8 directories accessed are kept cached; this really helps
- * the directory searches in unx2dos, but does eat some memory.
- *
- * entries are added to the cache by _free_symdir, and removed if they
- * fall off the end, or if they're retrieved by a subsequent _read_symdir.
- *
- * IMPLICIT ASSUMPTION: the same directory is never open more than once.
- */
-
- #define CACHESIZE 8
-
- static SYMDIR *in_cache;
-
- static
- SYMDIR *_cache_lookup(pth)
- const char *pth;
- {
- SYMDIR *prev = 0, *cur = in_cache;
-
- while (cur) {
- if (!strcmp(cur->s_pth, pth)) {
- /* remove from cache */
- if (prev)
- prev->s_nxt = cur->s_nxt;
- else
- in_cache = cur->s_nxt;
- cur->s_nxt = 0;
- return cur;
- }
- prev = cur; cur = cur->s_nxt;
- }
- return 0;
- }
-
- static
- void
- _cache_add(cur)
- SYMDIR *cur;
- {
- SYMDIR *nxt = 0;
- SYMENTRY *dir, *old;
-
- int count = 0;
-
- cur->s_nxt = in_cache;
- in_cache = cur;
- while (cur) {
- nxt = cur->s_nxt;
- ++count;
- if (count == CACHESIZE)
- cur->s_nxt = 0;
- else if (count > CACHESIZE) {
- dir = cur->s_dir;
- while (dir) {
- old = dir;
- dir = dir->next;
- free(old);
- }
- free(cur->s_pth);
- free(cur);
- }
- cur = nxt;
- }
- }
-
- /*
- * free a symbolic directory. Note that unx2dos is expecting the entries
- * to be accessible, i.e. it knows that we're caching at least 1 directory.
- * If this ever changes, change unx2dos.
- */
-
- void _free_symdir(dir)
- SYMDIR *dir;
- {
- if (dir)
- _cache_add(dir);
- }
-
- /*
- * read in the symbolic directory corresponding to "path".
- * the symdir must be removed from the cache, since it may
- * be modified and written back via _write_symdir
- */
-
- SYMDIR *_read_symdir(path)
- char *path;
- {
- char dirname[FILENAME_MAX], tmp[2*FILENAME_MAX], *p;
- int fd, c;
- SYMENTRY *old, *new;
- SYMDIR *dir;
-
- /* check that symbolic links are active */
- if (!_lOK) {
- errno = EINVAL;
- return NULL;
- }
-
- strcpy(dirname, path);
- strcat(dirname, "\\");
- strcat(dirname, _lDIR);
-
- if (dir = _cache_lookup(dirname))
- return dir;
-
- ResetFgetc();
- fd = Fopen(dirname, 0);
- if (fd < 0 && fd != -ENOENT) {
- errno = -fd;
- return NULL;
- }
-
- dir = (SYMDIR *)malloc(sizeof(SYMDIR)+strlen(tmp)+1);
- if (dir == NULL) {
- errno = ENOMEM;
- return dir;
- }
- dir->s_pth = strdup(dirname);
- if (!dir->s_pth)
- return NULL;
- dir->s_nxt = 0;
-
- old = NULL;
- if (fd == -ENOENT) goto done_directory;
-
- p = tmp;
- while ( (c = Fgetc(fd)) >= 0 ) {
- if (c == '\r') continue;
- if (c == '\n') {
- *p++ = 0;
- new= (SYMENTRY *)malloc(sizeof(SYMENTRY)+strlen(tmp)+1);
- if (new == 0) break;
- strcpy(new->linkname, tmp);
- new->linkto = new->linkname;
- for (p = new->linkname; *p; p++) {
- if (*p == '\t') {
- *p++ = 0;
- new->linkto = p;
- break;
- }
- }
- /*
- * Now we should check for any further fields, such as "flags"
- * it is very important that we save *all* the characters that were given
- * in the flags field, as well as setting the bits we understand.
- * That way, programs remain compatible with future versions of the
- * standard.
- */
- for (;*p;p++) {
- if (*p == '\t') {
- *p++ = 0;
- break;
- }
- }
- new->cflags = p; /* save pointer to flag characters */
- new->flags = 0;
- for (;*p;p++) {
- if (*p == 'A')
- new->flags |= SD_AUTO;
- }
- new->next = old;
- old = new;
- p = tmp;
- }
- else
- *p++ = c;
- }
- (void)Fclose(fd);
-
- done_directory:
- dir->s_dir = old;
- return dir;
- }
-
- /*
- * write a symbolic directory out onto a path
- */
-
- int _write_symdir(path, dir)
- char *path;
- SYMDIR *dir;
- {
- SYMENTRY *new;
- int fd, r;
- char dirname[FILENAME_MAX];
-
- /* check to see that symbolic links are OK */
- if (!_lOK)
- return -EINVAL;
-
- strcpy(dirname, path);
- strcat(dirname, "\\");
- strcat(dirname, _lDIR);
-
- fd = Fcreate(dirname, 0);
- if (fd < 0) {
- return fd;
- }
-
- for (new = dir->s_dir; new; new = new->next) {
- (void)Fwrite(fd, strlen(new->linkname), new->linkname);
- (void)Fwrite(fd, 1L, "\t");
- (void)Fwrite(fd, strlen(new->linkto), new->linkto);
- if (new->cflags[0]) {
- (void)Fwrite(fd, 1L, "\t");
- (void)Fwrite(fd, strlen(new->cflags), new->cflags);
- }
- r = Fwrite(fd, 1L, "\n");
- if (r <= 0) {
- (void)Fclose(fd);
- return r;
- }
- }
-
- (void)Fclose(fd);
- return 0;
- }
-
- /*
- * _symdir_lookup, _make_symlink: utility routines that are needed in
- * various places
- */
-
- /*
- * return the symbolic directory entry for "name", or NULL if it is not
- * found
- */
-
- SYMENTRY *
- _symdir_lookup(dir, name)
- SYMDIR *dir;
- const char *name;
- {
- SYMENTRY *ent;
-
- if (!dir) return 0;
- for (ent = dir->s_dir; ent; ent = ent->next) {
- if (!strcmp(ent->linkname, name))
- return ent;
- }
- return 0;
- }
-
- /*
- * _make_autolink(dosname, source): make an "automatic" symbolic link,
- * with name "source", to the file whose full canonical dos pathname is in
- * "dosname". Returns 1 if link made, 0 if not. It checks the _lAUTO
- * flag, so parent functions don't have to. Parents are responsible
- * for dealing with any conflicts with existing files.
- */
-
- int _make_autolink(dosname, source)
- char *dosname, *source;
- {
- char path[FILENAME_MAX], oldname[_LIB_NAME_MAX];
- char *s, *p;
- SYMDIR *dir;
- SYMENTRY *d;
-
- if (!_lAUTO)
- return 0;
-
- strcpy(path, dosname);
- if ((p = strrchr(path, '\\'))) {
- *p++ = 0;
- dos2unx(p, oldname);
- } else {
- dos2unx(path, oldname);
- path[0] = 0;
- }
-
- if (!(dir = _read_symdir(path)))
- return 0;
- d = (SYMENTRY *)
- malloc(sizeof(SYMENTRY)+strlen(source)+strlen(oldname)+4);
- if (d == 0) {
- errno = ENOMEM;
- return -1;
- _free_symdir(dir);
- }
- /*
- * now set up the fields; remember to set the character flags (cflags) as well!
- */
- strcpy(d->linkname, source);
- for (s = d->linkname; *s; s++)
- ;
- ++s;
- d->linkto = s;
- strcpy(s, oldname);
- for (; *s; s++)
- ;
- ++s;
- strcpy(s, "A"); /* AUTO flag */
- d->cflags = s;
- d->flags = SD_AUTO;
- d->next = dir->s_dir;
- dir->s_dir = d;
- _write_symdir(path, dir);
- return 1;
- }
-
-
- /**
- ** (sjk)++ Added a delete symdir cache from E. Roeder's library.
- **/
-
- static
- void
- _del_dir(cur)
- SYMDIR *cur;
- {
- SYMENTRY *dir, *old;
-
- dir = cur->s_dir;
- while (dir) {
- old = dir;
- dir = dir->next;
- free(old);
- }
- free(cur->s_pth);
- free(cur);
- }
-
- void
- _del_symdir_cache()
- {
- SYMDIR *cur = in_cache, *nxt = 0;
-
- while (cur) {
- nxt = cur->s_nxt;
- _del_dir(cur);
- cur = nxt;
- }
- in_cache = 0;
- }
-
-